#ifndef UUID_7A34FC96A4104354BA08B195A5EB10EC
#define UUID_7A34FC96A4104354BA08B195A5EB10EC

#include "../luautil/luautil.hpp"
#include <Box2D/Dynamics/b2World.h>
#include <Box2D/Dynamics/b2Fixture.h>
#include <gvl/hash_set/hash_set.hpp>

template<typename T>
struct NumberedIndex
{
	NumberedIndex()
	: first(0)
	{
	}

	NumberedIndex(unsigned firstInit, T secondInit)
	: first(firstInit)
	, second(secondInit)
	{
	}

	operator bool() const
	{ return first != 0; }

	gvl::hash_t hash(unsigned p) const
	{ return gvl::hash(first, p); }

	bool operator==(NumberedIndex const& other) const
	{ return first == other.first; }

	bool operator==(unsigned k) const
	{ return first == k; }

	unsigned first;
	T second;
};

struct LuaWorld : b2World, b2DestructionListener
{
	LuaWorld()
	: b2World(b2Vec2(0.f, 20.f), true)
	, nextBodyId(1)
	, nextShapeId(1)
	, nextJointId(1)
	{
		SetDestructionListener(this);
	}

	LuaWorld(LuaWorld const& other)
	: b2World(other)
	, nextBodyId(other.nextBodyId)
	, nextShapeId(other.nextShapeId)
	, nextJointId(other.nextJointId)
	{
		SetDestructionListener(this);

		for(b2Body* body = GetBodyList(); body; body = body->GetNext())
		{
			aliveBodies.insert(NumberedIndex<void*>(unsigned(body->GetUserData()), body));
		}
	}

	~LuaWorld()
	{
	}

	/*override*/ void SayGoodbye(b2Joint* joint)
	{
		
	}

	/*override*/ void SayGoodbye(b2Fixture* fixture)
	{
		unsigned id = (unsigned)fixture->GetUserData();
		aliveShapes.erase(id);
	}

	b2Body* check_body(lua_State* L, int idx)
	{
		unsigned id = luaL_checkint(L, idx);
		auto pair = aliveBodies.get(id);
		if(!pair)
			luaL_argerror(L, idx, "expected valid body");
		return static_cast<b2Body*>(pair->second);
	}

	unsigned nextBodyId;
	unsigned nextShapeId;
	unsigned nextJointId;
	gvl::hash_set_unboxed<NumberedIndex<void*> > aliveBodies;
	gvl::hash_set_unboxed<NumberedIndex<void*> > aliveShapes;
};

#endif // UUID_7A34FC96A4104354BA08B195A5EB10EC
